package org.ii.infrastructure.tiles.view;

import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tiles.TilesApplicationContext;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.context.TilesRequestContext;
import org.apache.tiles.impl.BasicTilesContainer;
import org.apache.tiles.servlet.context.ServletTilesApplicationContext;
import org.apache.tiles.servlet.context.ServletTilesRequestContext;
import org.apache.tiles.servlet.context.ServletUtil;
import org.springframework.web.servlet.support.JstlUtils;
import org.springframework.web.servlet.support.RequestContext;
import org.springframework.web.servlet.view.AbstractTemplateView;
import org.springframework.web.util.WebUtils;

/**
 * The Tiles integration in Spring 3.0 does not work with Tiles 2.2 and up. This is a copy of Springs
 * {@link org.springframework.web.servlet.view.tiles2.TilesView} with the changes necessary made.
 * <p/>
 * This is probably temporary until Spring includes the updates in a future version.
 * <p/>
 * The following changes are made:<br/>
 * 1. TilesView extends AbstractTemplateView instead of AbstractUrlBasedView<br/>
 * 2. The contents originally in method renderMergedOutputModel(..) is moved to renderMergedTemplateModel(..)
 * 
 * @see org.springframework.web.servlet.view.tiles2.TilesView
 */
public class TilesView extends AbstractTemplateView {
	@Override
	public boolean checkResource(final Locale locale) throws Exception {
		final TilesContainer container = ServletUtil.getContainer(getServletContext());
		if (! (container instanceof BasicTilesContainer)) {
			// Cannot check properly - let's assume it's there.
			return true;
		}
		final BasicTilesContainer basicContainer = (BasicTilesContainer)container;
		final TilesApplicationContext appContext = new ServletTilesApplicationContext(getServletContext());
		final TilesRequestContext requestContext = new ServletTilesRequestContext(appContext, null, null) {
			@Override
			public Locale getRequestLocale() {
				return locale;
			}
		};
		return (basicContainer.getDefinitionsFactory().getDefinition(getUrl(), requestContext) != null);
	}

	@Override
	protected void renderMergedTemplateModel(final Map<String, Object> model, final HttpServletRequest request, final HttpServletResponse response)
	throws Exception {
		final ServletContext servletContext = getServletContext();
		final TilesContainer container = ServletUtil.getContainer(servletContext);
		if (container == null) {
			throw new ServletException("Tiles container is not initialized. " + "Have you added a TilesConfigurer to your web application context?");
		}
		exposeModelAsRequestAttributes(model, request);
		JstlUtils.exposeLocalizationContext(new RequestContext(request, servletContext));
		if (!response.isCommitted()) {
			/*
			 * Tiles is going to use a forward, but some web containers (e.g. OC4J 10.1.3) do not properly expose the Servlet 2.4
			 * forward request attributes... However, must not do this on Servlet 2.5 or above, mainly for GlassFish
			 * compatibility.
			 */
			final ServletContext sc = getServletContext();
			if ( (sc.getMajorVersion() == 2) && (sc.getMinorVersion() < 5)) {
				WebUtils.exposeForwardRequestAttributes(request);
			}
		}
		container.render(getUrl(), request, response);
	}
}
